from __future__ import annotations

import httpx
import typing
import json

from .errors import DifyAPIError


class AsyncDifyServiceClient:
    """Dify Service API 客户端"""

    api_key: str
    base_url: str
    
    def __init__(
        self,
        api_key: str,
        base_url: str = "https://api.dify.ai/v1",
    ) -> None:
        self.api_key = api_key
        self.base_url = base_url

    async def chat_messages(
        self,
        inputs: dict[str, typing.Any],
        query: str,
        user: str,
        response_mode: str = "streaming",  # 当前不支持 blocking
        conversation_id: str = "",
        files: list[dict[str, typing.Any]] = [],
        timeout: float = 30.0,
    ) -> typing.AsyncGenerator[dict[str, typing.Any], None]:
        """发送消息"""
        if response_mode != "streaming":
            raise DifyAPIError("当前仅支持 streaming 模式")
        
        async with httpx.AsyncClient(
            base_url=self.base_url,
            trust_env=True,
            timeout=timeout,
        ) as client:
            async with client.stream(
                "POST",
                "/chat-messages",
                headers={"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"},
                json={
                    "inputs": inputs,
                    "query": query,
                    "user": user,
                    "response_mode": response_mode,
                    "conversation_id": conversation_id,
                    "files": files,
                },
            ) as r:
                async for chunk in r.aiter_lines():
                    if r.status_code != 200:
                        raise DifyAPIError(f"{r.status_code} {chunk}")
                    if chunk.strip() == "":
                        continue
                    if chunk.startswith("data:"):
                        yield json.loads(chunk[5:])
        
    async def workflow_run(
        self,
        inputs: dict[str, typing.Any],
        user: str,
        response_mode: str = "streaming",  # 当前不支持 blocking
        files: list[dict[str, typing.Any]] = [],
        timeout: float = 30.0,
    ) -> typing.AsyncGenerator[dict[str, typing.Any], None]:
        """运行工作流"""
        if response_mode != "streaming":
            raise DifyAPIError("当前仅支持 streaming 模式")
        
        async with httpx.AsyncClient(
            base_url=self.base_url,
            trust_env=True,
            timeout=timeout,
        ) as client:

            async with client.stream(
                "POST",
                "/workflows/run",
                headers={"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"},
                json={
                    "inputs": inputs,
                    "user": user,
                    "response_mode": response_mode,
                    "files": files,
                },
            ) as r:
                async for chunk in r.aiter_lines():
                    if r.status_code != 200:
                        raise DifyAPIError(f"{r.status_code} {chunk}")
                    if chunk.strip() == "":
                        continue
                    if chunk.startswith("data:"):
                        yield json.loads(chunk[5:])

    async def upload_file(
        self,
        file: httpx._types.FileTypes,
        user: str,
        timeout: float = 30.0,
    ) -> str:
        """上传文件"""
        async with httpx.AsyncClient(
            base_url=self.base_url,
            trust_env=True,
            timeout=timeout,
        ) as client:
            # multipart/form-data
            response = await client.post(
                "/files/upload",
                headers={"Authorization": f"Bearer {self.api_key}"},
                files={
                    "file": file,
                    "user": (None, user),
                },
            )

            if response.status_code != 201:
                raise DifyAPIError(f"{response.status_code} {response.text}")

            return response.json()
